package com.main.common.aspects;

import com.google.common.collect.ImmutableList;
import com.main.common.base.resp.RespBody;
import com.main.common.base.resp.RespCode;
import com.main.common.interfaces.PreventShaking;
import com.main.common.utils.exceptions.StackTraceLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Component
@Aspect
@Slf4j
public class PreventShakingAspect {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;;

    //DefaultRedisScript 是 Spring Data Redis 框架提供的一个类，用于简化在 Spring 应用程序中使用 Redis 脚本（如Lua脚本）的过程
    private static final DefaultRedisScript<Long>  DEFAULT_SCRIPT;
    //脚本静态代码块初始化
    static {
        DEFAULT_SCRIPT = new DefaultRedisScript<>();
        //在resources目录下导入脚本文件
        DEFAULT_SCRIPT.setLocation(new ClassPathResource("prevent_shaking.lua"));
        DEFAULT_SCRIPT.setResultType(Long.class);
    }

    @Pointcut("@annotation(com.main.common.interfaces.PreventShaking)")
    public void pointCut() {

    }


    @Around("pointCut()")
    public Object interceptor(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取执行的方法
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        PreventShaking shaking = method.getAnnotation(PreventShaking.class);
        String key = StringUtils.hasText(shaking.prefix()) ? shaking.prefix() : method.getName();
        // 设置方法参数作为变量
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((MethodSignature) signature).getParameterNames();
        List<Object> values = extractValues(paramNames, paramValues, shaking.keys(), shaking.delimiter());
        List<String> stringList = values.stream()
                .map(Object::toString) // 将每个元素转为 String
                .collect(Collectors.toList());
        String valuesString = String.join("", stringList);
        key = key + "_" + valuesString;
        ImmutableList<String> keys = ImmutableList.of(org.apache.commons.lang3.StringUtils.join(key));
        System.out.println(keys);
        System.out.println(shaking.expire());
        Long count = redisTemplate.execute(DEFAULT_SCRIPT, keys, shaking.expire());
        System.out.println(count);
        if (count != null && count > 0) {
            return joinPoint.proceed();
        } else {
            StackTraceLog stackTraceLog = new StackTraceLog();
            Exception e= new Exception(shaking.message());
            stackTraceLog.saveStackTraceLog(e);
            return RespBody.fail(RespCode.TOO_MANY_REQUESTS,shaking.message(),key);
        }
    }


    /**
     * 从参数中提取指定路径的值
     * @param paramNames 参数名数组（如 ["registerDTO"]）
     * @param paramValues 参数值数组（如 [registerDTO对象实例]）
     * @param keys 要提取的路径（如 "registerDTO.phone&registerDTO.email.value"）
     * @return 提取的值列表（如 ["22", "example@mail.com"]）
     */
    public static List<Object> extractValues(String[] paramNames, Object[] paramValues, String keys, String delimiter) {
        List<Object> result = new ArrayList<>();
        if (paramNames == null || paramValues == null || keys == null || paramNames.length != paramValues.length) {
            return result;
        }

        String[] keyPaths = keys.split(delimiter);
        for (String keyPath : keyPaths) {
            String[] parts = keyPath.split("\\.", 2); // 分割为参数名和剩余路径
            String paramName = parts[0];
            String remainingPath = (parts.length > 1) ? parts[1] : null;

            // 查找参数名对应的值
            for (int i = 0; i < paramNames.length; i++) {
                if (paramName.equals(paramNames[i])) {
                    Object paramValue = paramValues[i];
                    if (remainingPath == null) {
                        result.add(paramValue); // 直接添加参数对象
                    } else {
                        Object value = getFieldValue(paramValue, remainingPath);
                        result.add(value);
                    }
                    break;
                }
            }
        }
        return result;
    }

    /**
     * 递归获取对象的字段值
     */
    private static Object getFieldValue(Object obj, String fieldPath) {
        if (obj == null || fieldPath.isEmpty()) {
            return null;
        }

        String[] fields = fieldPath.split("\\.", 2);
        String currentField = fields[0];
        String remainingPath = (fields.length > 1) ? fields[1] : "";

        try {
            Field field = obj.getClass().getDeclaredField(currentField);
            field.setAccessible(true);
            Object value = field.get(obj);

            // 递归处理剩余路径（如嵌套对象）
            return remainingPath.isEmpty() ? value : getFieldValue(value, remainingPath);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            return null;
        }
    }

}